#include "pch.h"
#include "SyncWriteDataThread.h"
#include "SyncData.h"
#include "EnclaveProvider.h"
#include "ImportData.h"

SyncWriteDataThread::SyncWriteDataThread(SyncData *sync_data, Config *config, std::shared_ptr<EnclaveProvider> &enclave_provider)
	: sync_data_(sync_data), config_(config), hana_data_(config->database_), enclave_provider_(enclave_provider)
{
	value_buf = new char[value_buf_len];

	buf = new char[buf_len];
}


SyncWriteDataThread::~SyncWriteDataThread()
{
	if (value_buf)
	{
		delete[]value_buf;
	}

	if (buf)
	{
		delete[]buf;
	}
}

bool SyncWriteDataThread::runLoop()
{
	if (sync_data_->is_sync_finished() && sync_data_->popupSyncDatasSize() == 0)
	{
		LOG(INFO) << "Exit sync write data thread";
		return false;
	}

	WaitForSingleObject(sync_data_->event_.event_, INFINITE);

	std::shared_ptr<enclave::SyncTableRows> sync_table_rows;

	if (sync_data_->popupSyncDatas(sync_table_rows) == false)
	{
		LOG(INFO) << "popupSyncDatas false";
		return true;
	}

	if (sync_table_rows->rows().tablename().empty())
	{
		LOG(INFO) << "Can not get table name";
		return true;
	}

	std::vector<Field> &columns = sync_data_->tables_columns_[sync_table_rows->rows().tablename()];

	LOG(INFO) << "table: " << sync_table_rows->rows().tablename() << ", start = " << sync_table_rows->rows().pos() << ", end = "
		<< sync_table_rows->rows().pos() + sync_table_rows->rows().length() - 1;

	if (sync_table_rows->rows().rows_size() == 0)
	{
		LOG(INFO) << "rows_size == 0";
		return true;
	}

	LOG(INFO) << "Private decrypt, encrypt";

	for (int i = 0; i < sync_table_rows->rows().rows_size(); ++i)
	{
		auto values = sync_table_rows->rows().rows(i).values();

		memset(buf, 0, buf_len);

		enclave_provider_->private_key_decrypt(values.c_str(), (int)values.length(), buf, buf_len);

		int pos = 0;
		for (int j = 0; j < sync_table_rows->rows().rows(i).value_lens_size(); ++j)
		{
			int len = sync_table_rows->rows().rows(i).value_lens(j);

			if (std::find(ImportData::columns_ex_.begin(), ImportData::columns_ex_.end(), columns[j]) != ImportData::columns_ex_.end())
			{
				fields_.add_field(buf + pos, len);
			}
			else if (columns[j].type_ == "DECIMAL" || columns[j].type_ == "INTEGER")
			{
				fields_.add_field(buf + pos, len);
			}
			else {
				if (len == 0)
				{
					fields_.add_field(nullptr, 0);
				}
				else
				{
					memset(value_buf, 0, value_buf_len);
					int value_len = enclave_provider_->encrypt(buf + pos, len, value_buf, value_buf_len);

					if (value_len == 0)
					{
						LOG(INFO) << "Encrypt error, value = " << std::string(buf + pos, len);
						return true;
					}

					fields_.add_field(value_buf, value_len);
				}
			}

			pos += len;
		}
	}

	LOG(INFO) << "Private decrypt, encrypt end";

	LOG(INFO) << "Insert data to hana";

	if (hana_data_.insert_sync(sync_table_rows->rows().tablename(), fields_, sync_table_rows->rows().rows_size(), columns))
	{
		SyncDataCache::Data data;
		data.start_ = sync_table_rows->rows().pos();
		data.end_ = sync_table_rows->rows().pos() + sync_table_rows->rows().length() - 1;
		LOG(INFO) << "update cache file";
		sync_data_->sync_data_cache_.setSuccessed(sync_table_rows->rows().tablename(), data);
	}

	fields_.clear();

	LOG(INFO) << "Insert data to hana end";

	return true;
}
